package com.wootion.dizhi.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wootion.dizhi.dao.*;
import com.wootion.dizhi.entity.*;
import com.wootion.dizhi.exception.BusinessException;
import com.wootion.dizhi.response.Result;
import com.wootion.dizhi.service.MyPluginService;
import com.wootion.dizhi.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.*;
import java.lang.management.PlatformManagedObject;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MyPluginServiceImpl implements MyPluginService {
    @Resource
    private CategoryDao categoryDao;
    @Resource
    private PhotographDao photographDao;
    @Value(value = "${img.upload}")
    private String imgPath;

    @Value("${zip.upload}")
    private String zipDir;
    @Resource
    private ConfigurationDao configurationDao;
    @Resource
    private CylinderDao cylinderDao;
    @Resource
    private ResourcesDao resourcesDao;
    @Resource
    private DeviceMapper deviceMapper;
    /**
     * 野外数据归类照片收集-新建类别
     * @param category
     * @return
     */
    @Override
    public Result insertCategory(Category category) throws BusinessException {
        String pid = category.getPid();
        int rows = 0;
        //判断新建的类别是一级还是非一级的类别
        if(StringUtils.hasText(pid)){
            //如果pid不为空或者空字符串，那么代表新建的是二级或者三级
            //先去根据pid查询父级是第几级
            Category category1 = categoryDao.selectById(pid);
            String level = category1.getLevel();
            //检测父级等级，返回给子级的等级
            if(StringUtils.hasText(level)){
                switch (level){
                    case "1":
                        category.setLevel("2");
                        break;
                    case "2":
                        category.setLevel("3");
                        break;
                }
            }
            if(StringUtils.hasText(category.getLevel())){
                rows = categoryDao.insert(category);
            }else {
                throw new BusinessException("系统异常");
            }
        }else {
            //如果是一级标题，那么level是1 pid是null
            category.setLevel("1");
            category.setPid("-1");
            rows = categoryDao.insert(category);
        }
        return rows > 0 ? Result.success() : Result.error("新增类别失败");
    }

    /**
     * 野外数据归类照片收集-修改类别
     * @param category
     * @return
     */
    @Override
    public Result updateCategory(Category category) {
        int rows = categoryDao.updateById(category);
        return rows > 0 ? Result.success() : Result.error("修改失败");
    }

    /**
     * 野外数据归类照片收集-删除类别
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteCategory(String id) {
        List<String> list = new ArrayList<>();
        List<String> ids = this.recursionPid(list, id);
        //删除类别以及子类别
        categoryDao.deleteBatchIds(ids);
        //然后再删除关联的所有图片
        LambdaQueryWrapper<Photograph> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Photograph::getCategoryId,ids);
        photographDao.delete(queryWrapper);
        return Result.success();
    }

    /**
     * 野外数据归类照片收集-左侧树结构
     * @return
     */
    @Override
    public Result tree() {
        List<CategoryVo> tree = categoryDao.categoryPId("-1");
        return Result.success(tree);
    }

    /**
     * 野外数据归类照片收集-添加文件
     * @param id
     * @param multipartFiles
     * @return
     */
    @Override
    public Result addFile(String id, MultipartFile[] multipartFiles) {
        File imglFile = new File(imgPath);
        if(!imglFile.exists()){
            boolean mkdirs = imglFile.mkdirs();
            log.info("创建文件:{}",mkdirs ? "成功" : "失败");
        }
        for (MultipartFile multipartFile : multipartFiles) {
            //获取文件名称
            String fileName = multipartFile.getOriginalFilename();
            //获取文件后缀
            String suffix = "";
            if(StringUtils.hasText(fileName)){
                 suffix = fileName.substring(fileName.lastIndexOf("."));
            }
            // 拼接一个新的文件名称,以防文件名称重复，造成文件覆盖
            Photograph photograph = new Photograph();
            //设置文件原本的名称
            photograph.setFileName(fileName);
            //设置当前图片关联的类型id
            photograph.setCategoryId(id);
            //生成一个唯一的随机uuid
            String fileUuid = System.currentTimeMillis() + IdUtil.simpleUUID() + suffix;
            photograph.setFileUuid(fileUuid);
            try {
                //2:使用File类
                String savePath = imglFile.getPath() + File.separator + fileUuid;
                File saveFile = new File(savePath);
                //保存文件到磁盘上面
                FileCopyUtils.copy(multipartFile.getBytes(),saveFile);
                int rows = photographDao.insert(photograph);
                if(rows >0){
                    log.info("插入一条图片成功");
                }else {
                    log.error("插入一条图片失败，失败的图片名称是{}",fileName);
                }
            } catch (IOException e) {
                log.error("保存图片时出现异常");
                e.printStackTrace();
            }
        }
        return Result.success();
    }

    /**
     * 野外数据归类照片收集-文件分页列表
     * @param condition
     * @return
     */
    @Override
    public Result list(Condition condition) {
        List<String> list = new LinkedList<>();
        List<String> ids = this.recursionPid(list, condition.getId());
        Page<PhotographVo> page = new Page<>(condition.getPageNo(),condition.getPageSize());
        Page<PhotographVo> photographVoPage = photographDao.pageList(page, ids);
        //设置名字
        List<PhotographVo> photographVos = photographVoPage.getRecords();
        for (PhotographVo photographVo : photographVos) {
            String categoryId = photographVo.getCategoryId();
            Category category = categoryDao.selectById(categoryId);
            String level = category.getLevel();
            StringBuilder stringBuilder = new StringBuilder();
            if(StringUtils.hasText(level)){
                switch (level){
                    case "1":
                        stringBuilder.append(category.getCategoryName());
                     break;
                    case "2":
                        Category category1 = categoryDao.selectById(category.getPid());
                        stringBuilder.append(category1.getCategoryName()).append("/").append(category.getCategoryName());
                        break;
                    default:
                        Category category2 = categoryDao.selectById(category.getPid());
                        Category category3 = categoryDao.selectById(category2.getPid());
                        stringBuilder.append(category3.getCategoryName()).append("/").append(category2.getCategoryName()).append("/").append(category.getCategoryName());
                        break;
                }
            }
            photographVo.setCategoryName(stringBuilder.toString());
        }
        return Result.success(photographVoPage);
    }

    /**
     * 野外数据归类照片收集-修改文件名
     * @param photograph
     * @return
     */
    @Override
    public Result updateFileName(Photograph photograph) {
        String id = photograph.getId();
        String fileName = photograph.getFileName();
        if(!StringUtils.hasText(id) || !StringUtils.hasText(fileName)){
            return Result.error("文件名称不能为空");
        }
        Photograph photograph1 = photographDao.selectById(id);
        photograph1.setFileName(fileName);
        int rows = photographDao.updateById(photograph1);
        return rows > 0 ? Result.success() : Result.error("修改文件名称失败");
    }

    /**
     * 野外数据归类照片收集-删除文件(批量删除文件)
     * @param ids
     * @return
     */
    @Override
    public Result deleteFile(List<String> ids) {
        int i = photographDao.deleteBatchIds(ids);
        return i > 0 ? Result.success() : Result.error("文件删除失败");
    }

    /**
     * 野外数据归类照片收集-移动文件
     * @param moveVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result moveFile(MoveVo moveVo) {
        String id = moveVo.getId();
        List<String> ids = moveVo.getIds();
        for (String s : ids) {
            Photograph photograph = photographDao.selectById(s);
            photograph.setCategoryId(id);
            photographDao.updateById(photograph);
        }
        return Result.success();
    }

    /**
     * 野外数据归类照片收集-导出文件
     * @param id
     * @return
     */
    @Override
    public Result exportFile(String id) throws FileNotFoundException {
        Category category = categoryDao.selectById(id);

//        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(Category::getPid,id);
//        List<Category> categories = categoryDao.selectList(queryWrapper);
//        if(categories == null || categories.size()==0){
//            return Result.success();
//        }

        String exportPath = "./export/";
        File exportFile = new File(exportPath);
        if (!exportFile.exists()) {
            boolean mkdirs = exportFile.mkdirs();
            if (mkdirs) {
                log.info("创建文件夹{}成功", exportFile);
            } else {
                log.error("创建文件夹失败");
            }
        }
        String s = exportPath + category.getCategoryName()+"/";
        FileUtil.clean(exportFile);
        digui(category,s);
        //生成zip压缩包
        File exportDirFile = new File(zipDir);
        log.info("zipDir={}", zipDir);
        log.info("zipDir={}", exportDirFile.getPath());
        if (!exportDirFile.exists()) {
            boolean mkdirs = exportDirFile.mkdirs();
            if (mkdirs) {
                log.info("创建文件夹{}成功", exportDirFile);
            } else {
                log.error("创建文件夹失败");
            }
        }

        File file = new File("./export/"+category.getCategoryName());
        File absoluteFile = file.getAbsoluteFile();
        File file2 = new File(zipDir+"照片.zip/");
        File absoluteFile1 = file2.getAbsoluteFile();
        ZipUtil.zip(absoluteFile.getPath(),absoluteFile1.getPath(), true);
        return Result.success("./file/zip/照片.zip");
    }

    /**
     * 数据对比
     * @param address
     * @param experiment
     * @return
     */
    @Override
    public Result comparisonData(String address, String experiment) {
        //String addressExperiment = address + experiment;
        //此对象用来封装数据（液位计数据集合和色谱仪的数据集合）
        Comparison comparison = new Comparison();

        LambdaQueryWrapper<Configuration> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Configuration::getAddress,address);
        lambdaQueryWrapper.eq(Configuration::getExperiment,experiment);
        Configuration configuration = configurationDao.selectOne(lambdaQueryWrapper);
        if(configuration != null){
            String id = configuration.getId();
            LambdaQueryWrapper<Cylinder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Cylinder::getResId,id);
            queryWrapper.orderByAsc(Cylinder::getDateTime);
            List<Cylinder> cylinders = cylinderDao.selectList(queryWrapper);
            //封装数据体
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            List<ComData> comDatas = cylinders.stream().map(cylinder -> {
                ComData comData = new ComData();
                comData.setId(cylinder.getId());
                comData.setValue(cylinder.getCylinderData());
                String dateTime = cylinder.getDateTime();
                try {
                    Date parse = simpleDateFormat.parse(dateTime);
                    String format = simpleDateFormat.format(parse);
                    comData.setDateTime(format);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
                comData.setResId(cylinder.getResId());
                return comData;
            }).collect(Collectors.toList());
            comparison.setCylinderData(comDatas);

            LambdaQueryWrapper<Resources> queryWrapper2 = new LambdaQueryWrapper<>();
            queryWrapper2.eq(Resources::getResId,id);
            queryWrapper2.orderByAsc(Resources::getDate).orderByAsc(Resources::getTime);
            List<Resources> resources = resourcesDao.selectList(queryWrapper2);
            //封装数据体
            List<ComData> comDatas2 = resources.stream().map(resources1 -> {
                ComData comData = new ComData();
                comData.setId(resources1.getId());
                comData.setValue(resources1.getValue());
                String date = resources1.getDate();
                String time = resources1.getTime();
                String dateTime = date + " " + time;
                Date parse = null;
                try {
                    parse = simpleDateFormat.parse(dateTime);
                    String format = simpleDateFormat.format(parse);
                    comData.setDateTime(format);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
                comData.setResId(resources1.getResId());
                return comData;
            }).collect(Collectors.toList());
            comparison.setResData(comDatas2);
        }
        return Result.success(comparison);
    }

    /**
     * 选择设备和次序号
     * @param address
     * @return
     */
    @Override
    public Result selectDevice(String address) {
        //如果是空，那么查询全部设备
        if(!StringUtils.hasText(address)){
            LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.groupBy(Device::getId);
            List<Device> devices = deviceMapper.selectList(queryWrapper);
            return Result.success(devices);
        }else {
            LambdaQueryWrapper<Configuration> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Configuration::getAddress,address);
            List<Configuration> configurations = configurationDao.selectList(queryWrapper);
            return Result.success(configurations);
        }
    }


    public List<String> recursionPid(List<String> ids,String id){
        //不管有没有查询到子类，这个父类id一定需要
        ids.add(id);
        //先去获取所有pid=id的子类，以及子类的子类，直到为null为止
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Category::getPid,id);
        List<Category> categories = categoryDao.selectList(lambdaQueryWrapper);
        //如果不为null的话，继续向下在找
        if(!CollectionUtils.isEmpty(categories)){
            for (Category category : categories) {
                ids.add(category.getId());
                lambdaQueryWrapper.clear();
                lambdaQueryWrapper.eq(Category::getPid,category.getId());
                List<Category> categories2 = categoryDao.selectList(lambdaQueryWrapper);
                if(!CollectionUtils.isEmpty(categories2)){
                    for (Category category1 : categories2) {
                        ids.add(category1.getId());
                    }
                }
            }
        }
        return ids;
    }

    public void digui(Category category,String target){
        if (!category.getLevel().equals("3")){
            QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("pid",category.getId());
            List<Category> categories1 = categoryDao.selectList(queryWrapper);
            categories1.forEach(category1 -> {
                digui(category1,target+category1.getCategoryName()+"/");
            });
            //文件操作
            QueryWrapper<Photograph> photographQueryWrapper = new QueryWrapper<>();
            photographQueryWrapper.eq("categoryId",category.getId());
            List<Photograph> photographs = photographDao.selectList(photographQueryWrapper);
            FileUtil.mkdir(target);
            photographs.forEach(photograph -> {
                // 复制文件
                //FileUtil.copy(imgPath+photograph.getFileUuid(), target+photograph.getFileName(), true);
                BufferedInputStream in = FileUtil.getInputStream(new File(imgPath+photograph.getFileUuid()));
                BufferedOutputStream out = FileUtil.getOutputStream(new File(target+photograph.getFileName()));
                IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE);
                try {
                    in.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
//                copyFile(imgPath+photograph.getFileUuid(),target);
            });


        }else {
            QueryWrapper<Photograph> photographQueryWrapper = new QueryWrapper<>();
            photographQueryWrapper.eq("categoryId",category.getId());
            List<Photograph> photographs = photographDao.selectList(photographQueryWrapper);
            FileUtil.mkdir(target);
            photographs.forEach(photograph -> {
                // 复制文件
                //FileUtil.copy(imgPath+photograph.getFileUuid(), target+photograph.getFileName(), true);
                BufferedInputStream in = FileUtil.getInputStream(new File(imgPath+photograph.getFileUuid()));
                BufferedOutputStream out = FileUtil.getOutputStream(new File(target+photograph.getFileName()));
                IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE);
                try {
                    in.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

}
